#include <Windows.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <errno.h>
#include <string.h>
#include <Psapi.h>
//#include <TlHelp32.h>

#define BUFSIZE 255
#define LINES "==============================================================================="
#define VERSION "1.1"
#define LAST_UPDATE "2011/06/10"

/** 텍스트 출력 함수 관련 매크로 상수 **/
//텍스트 출력 정렬
#define LEFT -1
#define CENTER 0
#define RIGHT 1
//기본 좌표/
#define DEFAULT -1

/** 프로세스 리스트 저장 구조체 **/
struct _PLIST{
	char path[BUFSIZE];
	int pid;
	struct _PLIST* next;
};
typedef struct _PLIST PLIST;


/** 제거 결과 출력용 전역 변수 **/
int g_Removed_Process_Count=0;
int g_Removed_File_Count=0;			//제거된 파일 수
int g_Removed_Registry_Count=0;		//제거된 레지스트리 수
int g_Removed_Service_Count=0;		//제거된 서비스 수

/* 히든 프로세스를 찾지 못하는 검색 방법 (TlHelp32.h 인클루드 필요)
int SearchPid(char* fileName){
	PROCESSENTRY32 procEntry={0};
	HANDLE hSnapshot;
	int pid=0;

	hSnapshot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);

	procEntry.dwSize=sizeof(procEntry);
	Process32First(hSnapshot,&procEntry);

	do{
		if(!strcmp(fileName,procEntry.szExeFile)){
			pid=procEntry.th32ProcessID;
			break;
		}
	}while(Process32Next(hSnapshot,&procEntry));

	CloseHandle(hSnapshot);

	printf("Backdoor PID is %d \n",pid);

	return pid;
}
*/

//텍스트 프린트/
void printText(char* buffer,int x,int y,int align){
	COORD cr;
	CONSOLE_SCREEN_BUFFER_INFO info;
	int width;	//콘솔 너비
	int height;	//콘솔 높이

	GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),&info);

	width=info.srWindow.Right-info.srWindow.Left;
	height=info.srWindow.Bottom-info.srWindow.Top;

	if(x == DEFAULT){
		x=0;
	}
	if(y == DEFAULT){
		y=info.dwCursorPosition.Y;
	}

	if(align == CENTER){
		cr.X=(width-(strlen(buffer)+x))/2;
	}else if(align == RIGHT){
		cr.X=width-(strlen(buffer)+x);
	}else{
		cr.X=x;
	}

	if(cr.X < 0){
		cr.X=0;
	}
	cr.Y=y;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),cr);
	puts(buffer);
}

//프로세스 리스트 제거
void DeleteProcessList(PLIST* pList){
	PLIST* tempList;

	if(pList == NULL){
		return;
	}

	while(pList->next != NULL){
		tempList=pList->next->next;
		free(pList->next);
		pList->next=tempList;
	}
	free(pList);

}

//프로세스 리스트 저장
PLIST* GetProcessList(){
	PLIST* pList=NULL;
	PLIST* tempList;
	PLIST* nextList;
	HANDLE hProc;
	HMODULE hMod;
	DWORD cbNeeded;
	char buffer[BUFSIZE];
	int pid;

	//BruteForce 식 스캔을 통해 pid를 검색하여 숨겨진 프로세스를 찾는다.
	for(pid=0;pid <= 16860;pid++){

		hProc=OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,FALSE,pid);

		if(hProc == NULL){
			continue;
		}

		EnumProcessModules(hProc,&hMod,sizeof(hMod),&cbNeeded);

		GetModuleFileNameExA(hProc,hMod,buffer,BUFSIZE-1);

		//구조체 저장
		tempList=(PLIST*)malloc(sizeof(PLIST));

		strcpy(tempList->path,buffer);
		tempList->pid=pid;
		tempList->next=NULL;

		if(pList == NULL){
			pList=tempList;
			nextList=pList;
		}else{
			nextList->next=tempList;
			nextList=nextList->next;
		}

		CloseHandle(hProc);
	}

	return pList;
}


//IRCBot 여부 검사
int CheckFile(char* pPath){
	FILE* fp;
	char buffer[BUFSIZE]={0};
	
	fp=fopen(pPath,"r");
	fgets(buffer,13,fp);
	buffer[12]=0;

	fclose(fp);

	if(!strcmp(buffer,"MZfarbrausch")){
		return 1;
	}
	return 0;
}

//프로세스 제거
int KillProcess(int pid){
	HANDLE hProc;

	hProc=OpenProcess(PROCESS_TERMINATE,FALSE,pid);

	if(!hProc){
		return GetLastError();
	}

	TerminateProcess(hProc,0);

	g_Removed_Process_Count++;
	printf("IRCBot Process Killed!! (PID : %d) \n",pid);

	CloseHandle(hProc);

	return 0;
}

//프로세스 탐색 및 제거
void HuntProcess(PLIST* pList,char* pPath){
	int i;
	PLIST* nextList;

	if(pList == NULL){
		puts("Process List is NULL!!");
		return;
	}

	//슬래시(/)를 백슬래시(\)로 변환
	for(i=0;*(pPath+i) != 0 ; i++){
		if(*(pPath+i) == 47){
			*(pPath+i) = 92;
		}
	}

	nextList=pList;
	while(nextList != NULL){
		if(!strcmp(nextList->path,pPath)){
			//실행중인 IRCBot 종료
			KillProcess(nextList->pid);
		}
		nextList=nextList->next;
	}
}

//IRCBot이 생성한 레지스트리 제거
void RemoveReg(){
	HKEY hkey;

	RegOpenKey(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",&hkey);

	if(RegDeleteValue(hkey,"WSSVC") == ERROR_SUCCESS){
		g_Removed_Registry_Count++;
	}

	RegCloseKey(hkey);

	RegOpenKey(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Services\\SharedAccess\\Parameters\\FirewallPolicy\\StandardProfile\\AuthorizedApplications\\List",&hkey);
	
	if(RegDeleteValue(hkey,"C:\\WINDOWS\\system\\smsc.exe") == ERROR_SUCCESS){
		g_Removed_Registry_Count++;
	}
    
	RegCloseKey(hkey);

	if(RegDeleteKey(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Minimal\\SVCWINSPOOL") == ERROR_SUCCESS){
		g_Removed_Registry_Count++;
	}

	if(RegDeleteKey(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Network\\SVCWINSPOOL") == ERROR_SUCCESS){
		g_Removed_Registry_Count++;
	}
	if(g_Removed_Registry_Count != 0){
		puts("Malicious Registry Deleted!!");
	}
}

//IRCBot이 생성한 서비스 제거
void RemoveService(){
	SC_HANDLE hManager;
	SC_HANDLE hService;
	SERVICE_STATUS sStat;
	char path[BUFSIZE];

	hManager=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);

	hService=OpenService(hManager,"sysdrv32",SERVICE_ALL_ACCESS);

	if(hService){
		ControlService(hService,SERVICE_CONTROL_STOP,&sStat);

		while(QueryServiceStatus(hService,&sStat)){
			if(sStat.dwCurrentState == SERVICE_STOP_PENDING){
				Sleep(1000);
			}else{
				break;
			}
		}

		if(sStat.dwCurrentState == SERVICE_STOPPED){
			if(DeleteService(hService)){
				g_Removed_Service_Count++;
				puts("sysdrv32 Service Deleted!!");
			}
		}
		CloseServiceHandle(hService);
	}

	GetWindowsDirectory(path,BUFSIZE);

	strcat(path,"\\system32\\drivers\\sysdrv32.sys");

	if(DeleteFile(path)){
		g_Removed_File_Count++;
		printf("%s Deleted!!\n",path);
	}

	CloseServiceHandle(hManager);
}

//파일 탐색
void SearchFile(PLIST* pList,char* pPath){
	struct _finddatai64_t c_file;
	intptr_t hFile;
	char dirPath[BUFSIZE];
	char tempPath[BUFSIZE];
	int i;

	//디렉토리 경로명만 추출하는 작업(현재 경로명에서 *.* 제거)
	strcpy(dirPath,pPath);
	i=strlen(dirPath)-4;
	dirPath[i]=0;

	//파일 검색 시작
	hFile=_findfirsti64(pPath,&c_file);

	if(hFile == -1L){
		return;
	}

	while(_findnexti64(hFile,&c_file) == 0){
		if(!strcmp(c_file.name,".") || !strcmp(c_file.name,"..")){
			continue;
		}

		//디렉토리 발견시 파일 검색 함수 재귀호출
		if(c_file.attrib & _A_SUBDIR){
			sprintf(tempPath,"%s/%s/*.*",dirPath,c_file.name);
			SearchFile(pList,tempPath);
			continue;
		}

		//23552 byte 파일 발견시 Backdoor.Win32.IRCBot.23552 체크 함수 호출
		if(c_file.size == 23552){
			sprintf(tempPath,"%s/%s",dirPath,c_file.name);

			//IRCBot 패턴 체크
			if(CheckFile(tempPath)){
				printf("%s is IRCBot!!\n",tempPath);

				HuntProcess(pList,tempPath);
				SetFileAttributes(tempPath,FILE_ATTRIBUTE_NORMAL);

				for(i=0 ; i < 10 ; i++){
					if(DeleteFile(tempPath)){
						g_Removed_File_Count++;
						printf("%s Deleted!!\n",tempPath);
						break;
					}
					Sleep(500);
				}
				if(i == 10){
					printf("Delete %s Failed!!\n",tempPath);
				}
			}
		}
	}
	
}

int main(){
	PLIST* pList=NULL;
	int cnt;
	int i;
	int drvType;
	char buffer[BUFSIZE];
	char drvRoot[104];
	char path[7]="A:/*.*";

	system("cls");

	//초기 타이틀 출력
	printText(LINES,DEFAULT,DEFAULT,LEFT);
	sprintf(buffer,"Win32.Backdoor.Worm.IRCBot.23552 Removal Tool v%s",VERSION);
	printText(buffer,DEFAULT,DEFAULT,CENTER);
	puts("");
	printText("Created by Kim bu Seong",1,DEFAULT,RIGHT);
	printText("http://kbs3720.tistory.com",1,DEFAULT,RIGHT);
	sprintf(buffer,"Last Update : %s",LAST_UPDATE);
	printText(buffer,1,DEFAULT,RIGHT);
	printText(LINES,DEFAULT,DEFAULT,LEFT);


	//레지스트리 정리
	RemoveReg();
	//서비스 정리
	RemoveService();

	//프로세스 리스트 획득
	pList=GetProcessList();

	//드라이브 목록을 불러옴
	cnt=GetLogicalDriveStrings(104,drvRoot);

	for(i=0;i<cnt;i+=4){
		path[0]=drvRoot[i];

		drvType = GetDriveType(&drvRoot[i]);

		//플로피 디스크 건너 뜀
		if(path[0] < 'C'){
			continue;
		}

		if(drvType == DRIVE_FIXED || drvType == DRIVE_REMOVABLE || drvType == DRIVE_RAMDISK ){
			//로컬 디스크, 이동식 디스크, 램디스크인 경우에 파일 탐색
			SearchFile(pList,path);
		}

	}

	//실행 결과 출력
	printText(LINES,DEFAULT,DEFAULT,LEFT);
	sprintf(buffer,"Total Removal Count");
	printText(buffer,DEFAULT,DEFAULT,CENTER);
	sprintf(buffer,"Process : %d  File : %d  Registry : %d  Service : %d",g_Removed_Process_Count,g_Removed_File_Count,g_Removed_Registry_Count,g_Removed_Service_Count);
	printText(buffer,DEFAULT,DEFAULT,CENTER);
	printText(LINES,DEFAULT,DEFAULT,LEFT);

	//프로세스 리스트 제거
	DeleteProcessList(pList);

	system("pause");

	return 0;
}